<?php
/*
	本插件：$this->model('model')->方法名();
	其他地方调用：model('jy_aixiaoyi/model')->方法名();
*/
namespace jy_aixiaoyi;
defined('BY_JYA') or exit('error');
require_once ROOT_PLUGIN.'jy_aixiaoyi/vendor/autoload.php';
use WebSocket\Client;
class xinghuo extends \plugin{
	//获取聊天文本
	public function getmsg($content,$isexi=false) {
		$basic=$this->plugin_setting('basic');
		if(!$basic['xf_appid']){
			if($isres){
				$res['choices'][0]['text']='chatAI暂时无法使用，请联系管理员，设置好基本参数星火appid';
				return $res;
			}else{
				exi('chatAI暂时无法使用，请联系管理员，设置好基本参数appid','error');
			}
		}
		if(!$basic['xf_apisecret']){
			if($isres){
				$res['choices'][0]['text']='chatAI暂时无法使用，请联系管理员，设置好基本参数星火apisecret';
				return $res;
			}else{
				exi('chatAI暂时无法使用，请联系管理员，设置好基本参数星火apisecret','error');
			}
		}
		if(!$basic['xf_apikey']){
			if($isres){
				$res['choices'][0]['text']='chatAI暂时无法使用，请联系管理员，设置好基本参数星火apikey';
				return $res;
			}else{
				exi('chatAI暂时无法使用，请联系管理员，设置好基本参数星火apikey','error');
			}
		}
		if($basic['isku']){
			$msg=$this->model('model')->getwenda($content);
			if($msg){
				return $msg;
			}
		}
		if(strpos($basic['apis'],'3') !== false){
			
		}else{
			if(strpos($basic['apis'],'1') !== false){
				return $this->model('tuling')->getmsg($content,$isexi);
			}
			return '';
		}
		//return '这里是测试数据！这里是测试数据！这里是测试数据！这里是测试数据！这里是测试数据！这里是测试数据！';
		$addr = "wss://aichat.xf-yun.com/v1/chat";
		$authUrl = $this->assembleAuthUrl("GET",$addr,$basic['xf_apikey'],$basic['xf_apisecret']);
		//创建ws连接对象
		$client = new Client($authUrl);
			// 连接到 WebSocket 服务器
			if ($client) {
				// 发送数据到 WebSocket 服务器
				$data = $this->getBody($basic['xf_appid'],$content);
				$client->send($data);
				// 从 WebSocket 服务器接收数据
				$answer = "";
				while(true){
					$response = $client->receive();
					$resp = json_decode($response,true);
					$code = $resp["header"]["code"];
					if(0 == $code){
						$status = $resp["header"]["status"];
						if($status != 2){
							$content = $resp['payload']['choices']['text'][0]['content'];
							$answer .= $content;
						}else{
							$content = $resp['payload']['choices']['text'][0]['content'];
							$answer .= $content;
							$total_tokens = $resp['payload']['usage']['text']['total_tokens'];
							break;
						}
					}else{
					    $error_msg=$code.",".$resp["header"]["message"];
						break;
					}
				}
			} else {
				$error_msg="无法连接到 WebSocket 服务器";
			}
		if($error_msg){
			if(strpos($basic['apis'],'1') !== false){
				return $this->model('tuling')->getmsg($content,$isexi);
			}
			if($isexi){
				exi('获取失败：'.$error_msg,'error');
			}else{
				return $basic['nomsg']?:'chatAI暂时无法回答您的问题！请联系管理员！';
			}
		}
		if($answer){
			$this->model('model')->upwenda($content,$answer);
		}
		return $answer;
	}
	//构造参数体
	public function getBody($appid,$question){
			$header = array(
				"app_id" => $appid,
				"uid" => $_SESSION['uid']
			);
			$parameter = array(
				"chat" => array(
					"domain" => "general",
					"temperature" => 0.5,
					"max_tokens" => 1024
				)
			);
			$payload = array(
				"message" => array(
					"text" => array(
						// 需要联系上下文时，要按照下面的方式上传历史对话
						// array("role" => "user", "content" => "你是谁"),
						// array("role" => "assistant", "content" => "....."),
						// ...省略的历史对话
						array("role" => "user", "content" => $question)
					)
				)
			);
			$json_string = json_encode(array(
				"header" => $header,
				"parameter" => $parameter,
				"payload" => $payload
			));
			return $json_string;

	}
	//鉴权方法
	public function assembleAuthUrl($method, $addr, $apiKey, $apiSecret) {
			if ($apiKey == "" && $apiSecret == "") { // 不鉴权
				return $addr;
			}
			
			$ul = parse_url($addr); // 解析地址
			if ($ul === false) { // 地址不对，也不鉴权
				return $addr;
			}
			// // $date = date(DATE_RFC1123); // 获取当前时间并格式化为RFC1123格式的字符串
			$timestamp = time();
			$rfc1123_format = gmdate("D, d M Y H:i:s \G\M\T", $timestamp);
			// $rfc1123_format = "Mon, 31 Jul 2023 08:24:03 GMT";
			// 参与签名的字段 host, date, request-line
			$signString = array("host: " . $ul["host"], "date: " . $rfc1123_format, $method . " " . $ul["path"] . " HTTP/1.1");
			
			// 对签名字符串进行排序，确保顺序一致
			// ksort($signString);
			// 将签名字符串拼接成一个字符串
			$sgin = implode("\n", $signString);
			//print( $sgin);
			// 对签名字符串进行HMAC-SHA256加密，得到签名结果
			$sha = hash_hmac('sha256', $sgin, $apiSecret,true);
			//print("signature_sha:\n");
			//print($sha);
			$signature_sha_base64 = base64_encode($sha);
			
			// 将API密钥、算法、头部信息和签名结果拼接成一个授权URL
			$authUrl = "api_key=\"$apiKey\", algorithm=\"hmac-sha256\", headers=\"host date request-line\", signature=\"$signature_sha_base64\"";
			
			// 对授权URL进行Base64编码，并添加到原始地址后面作为查询参数
			$authAddr = $addr . '?' . http_build_query(array(
				'host' => $ul['host'],
				'date' => $rfc1123_format,
				'authorization' => base64_encode($authUrl),
			));
			
			return $authAddr;
	}
}
?>